/***************************************************************************
 *   This is a part of the NextCAD Web APP.                                *
 *   Copyright (C) AMCAX, All rights reserved.                             *
 ***************************************************************************/

import { pickedLineData, pickedVertexData, pickedFaceData } from '@amcax/base';

import {
  NumberInputFormat,
  PickInputRJSFFormat,
} from '@app-cad/common/components/command-form/constants';
import { NonDialogPickableCommandForm } from '@app-cad/common/components/command-form/pickable';
import { useCommand } from '@app-cad/common/hooks/useCommand';
import { useTools } from '@app-cad/common/hooks/useTools';
import { MessageTip } from '@app-cad/common/utils/MessageTip';
import { RJSFSchema } from '@rjsf/utils';
import { useAsyncEffect } from 'ahooks';
import { useEffect, useMemo, useState } from 'react';
import { ChildLineCommandProps } from './types';
import { omitBy } from 'lodash';
import { getIdOfPickedObj } from '@app-base/common/utils/render';

type pickedExtendToDataType =
  | pickedLineData
  | pickedVertexData
  | pickedFaceData;

type Params = {
  mode: '2point';
  point1: string;
  point2: string;
  p1Offset: number;
  p1Extendto?: string;
  p2Offset: number;
  p2Extendto?: string;
  useMirror?: boolean;
};

type FormData = {
  point1?: pickedVertexData;
  point2?: pickedVertexData;
  p1Offset: number;
  p1Extendto?: pickedExtendToDataType;
  p2Offset: number;
  p2Extendto?: pickedExtendToDataType;
  useMirror?: boolean;
};

export const BetweenDot = ({
  onClose,
  props,
  editDxid,
}: ChildLineCommandProps) => {
  const defaultForm = {
    useMirror: false,
    p1Offset: 0,
    p2Offset: 0,
    p1Extendto: null,
    p2Extendto: null,
  } as FormData;

  const { picker } = useTools();
  const [formData, setFormData] = useState<FormData>(defaultForm);

  useAsyncEffect(async () => {
    if (props == null) {
      setFormData(defaultForm);
      return;
    }

    const params = props.params as Params;

    await initEditDependency([
      params.point1,
      params.point2,
      params.p1Extendto,
      params.p2Extendto,
    ]);

    const { point1, point2, p1Offset, p1Extendto, p2Offset, p2Extendto } =
      params;

    setFormData({
      point1: picker.generatePickObjByPickID(point1) as pickedVertexData,
      point2: picker.generatePickObjByPickID(point2) as pickedVertexData,
      p1Offset: p1Offset,
      p1Extendto: p1Extendto
        ? (picker.generatePickObjByPickID(p1Extendto) as pickedExtendToDataType)
        : undefined,
      p2Offset: p2Offset,
      p2Extendto: p2Extendto
        ? (picker.generatePickObjByPickID(p2Extendto) as pickedExtendToDataType)
        : undefined,
      useMirror: params.useMirror ?? false,
    });
  }, [editDxid]);

  useEffect(() => {
    preview();
  }, [formData]);

  const isFormDataValid = () => {
    if (formData.point1 == null || formData.point2 == null) {
      return false;
    }

    return true;
  };

  const preview = async () => {
    clear();
    if (!isFormDataValid()) {
      return;
    }

    await execute(true);
  };

  const checkAndFinishDraw = async () => {
    clear();
    if (!isFormDataValid()) {
      return;
    }

    await execute(false);

    onClose();
  };

  const { initEditDependency, initingEdit, clear, confirmCommand, isLoading } =
    useCommand('cmd-line-between-dot', {
      commandName: 'CreateCurve',
      editDxid: props?.shape,
      onClose,
      finishDraw: checkAndFinishDraw,
    });

  const execute = (preview: boolean) => {
    const { point1, point2 } = formData;

    const p1Extendto = getIdOfPickedObj(formData.p1Extendto);
    const p2Extendto = getIdOfPickedObj(formData.p2Extendto);

    const params = omitBy(
      {
        mode: '2point',
        point1: point1.vertexId,
        point2: point2.vertexId,

        p1OffsetMode: p1Extendto ? 'extendTo' : 'length',
        p1Extendto: p1Extendto,
        p1Offset: p1Extendto ? null : formData.p1Offset, // 如果p1Extendto存在，则p1Offset不需要,

        p2OffsetMode: p2Extendto ? 'extendTo' : 'length',
        p2Extendto: p2Extendto,
        p2Offset: p2Extendto ? null : formData.p2Offset, // 如果p2Extendto存在，则p2Offset不需要
        useMirror: formData.useMirror ?? false,
      },
      (val) => val == null,
    );

    return confirmCommand(
      {
        a: params,
        type: 'Line',
      },
      preview,
    );
  };

  const schema: RJSFSchema = useMemo(() => {
    const properties = omitBy(
      {
        point1: {
          type: 'string',
          format: PickInputRJSFFormat.PickVertex,
        },
        point2: {
          type: 'string',
          format: PickInputRJSFFormat.PickVertex,
        },
        p1Offset: {
          type: 'number',
          title: '起点',
          default: 0,
          minimum: 0,
          format: NumberInputFormat.Length,
        },
        p1Extendto: {
          type: 'string',
          title: '直到1',
          format: PickInputRJSFFormat.PickFrameReference,
        },
        p2Offset: {
          type: 'number',
          title: '终点',
          default: 0,
          minimum: 0,
          format: NumberInputFormat.Length,
        },
        p2Extendto: {
          type: 'string',
          title: '直到2',
          format: PickInputRJSFFormat.PickFrameReference,
        },
        useMirror:
          /** 1. 当两侧的限制类型均为尺寸时，具有该选项。
           *  2. 当起点处的限制类型为直到元素（无论第二个类型是什么）时，具有该选项。*/
          (formData.p1Extendto == null && formData.p2Extendto == null) ||
          formData.p1Extendto != null
            ? {
                type: 'boolean',
                title: '镜像范围',
                default: false,
              }
            : null,
      },
      (val) => val == null,
    );

    return {
      type: 'object',
      properties,
    } as RJSFSchema;
  }, [formData.p1Extendto, formData.p2Extendto]);

  const extraUiSchema = useMemo(() => {
    const properties = omitBy(
      {
        point1: {
          'ui:placeholder': '请输入起点',
          'ui:autofocus': true,
        },
        point2: {
          'ui:placeholder': '请输入终点',
        },
        p1Offset: {
          'ui:disabled': formData.p1Extendto != null,
        },
        p1Extendto: {
          'ui:placeholder': '请选择延伸到1',
        },
        p2Offset: {
          'ui:disabled': formData.p2Extendto != null || formData.useMirror,
        },
        p2Extendto: {
          'ui:placeholder': '请选择延伸到2',
          'ui:disabled': formData.useMirror,
        },
      },
      (val) => val == null,
    );

    return properties;
  }, [formData.p1Extendto, formData.p2Extendto, formData.useMirror]);

  return (
    <NonDialogPickableCommandForm
      className='-mt-3'
      disabled={initingEdit}
      submitLoading={isLoading}
      schema={schema}
      onCancel={onClose}
      formData={formData}
      onChange={(v) => {
        if (v.point1 != null && v.point2 != null) {
          const startVertext = v.point1.assisObj.getVertex();
          const endVertext = v.point2.assisObj.getVertex();
          if (startVertext.distanceTo(endVertext) === 0) {
            if (formData.point1 == null) {
              v.point1 = null; // 如果之前point1为空，则保持为空
            } else if (formData.point2 == null) {
              v.point2 = null; // 如果之前point2为空，则保持为空
            }

            MessageTip.error('起点和终点不可重合');
          }
        }

        if (v.useMirror) {
          if (v.p1Extendto != null) {
            v.p2Extendto = null; // 如果p1Extendto存在，则p2Extendto不需要
          } else if (v.p1Offset != v.p2Offset) {
            v.p2Offset = v.p1Offset; // 如果p1Offset存在，则p2Offset和 p1Offset 保持一致
          }
        }
        setFormData(v);
      }}
      extraUiSchema={extraUiSchema}
      submitText='完成'
      onSubmit={checkAndFinishDraw}
      isFormDataValid={isFormDataValid()}
    />
  );
};
